{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 230,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 230,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### pry-docの読み込み\n",
    "require \"/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "#require \"/root/git_jupyter_notebook/Ruby/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "#require \"/Users/ftakao2007/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# ブロックとProc\n",
    "\n",
    "* ブロック\n",
    "    * 新たにスコープを作成する\n",
    "        * for式、if式、while式などはスコープは作成されない\n",
    "    * <font color=\"red\">メソッドを呼び出すときのみ記述できる</font>\n",
    "    * yieldという式を使う事でブロック内部で記述した式を呼び出すことができる\n",
    "    * 「{}」と「do ～ end」の形式で書ける\n",
    "        * 傾向\n",
    "            * 1行で書けるときは{}\n",
    "            * 複数行で書く時は do end\n",
    "            \n",
    "* 参考\n",
    "    * [メタプログラミングRuby 第3章 まとめ　(ブロック)](http://portaltan.hatenablog.com/entry/2015/07/17/181358)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 186,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "3\n",
      "unexpected return\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  yield\n",
    "end\n",
    "\n",
    "puts func{ 1 }\n",
    "puts func{ x = 2 }\n",
    "puts func{ x = 2; y = 3}\n",
    "puts func{ x = 2; y = 3; z = 4}\n",
    "puts func{ x = 2; next y = 3; z = 4}\n",
    "begin\n",
    "  puts func{ x = 2; return y = 3; z = 4}\n",
    "rescue LocalJumpError => ex\n",
    "  puts ex\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 194,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "3\n",
      "end\n",
      "\n",
      "1\n",
      "end\n",
      "\n",
      "1\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  ary = [1,2,3]\n",
    "  ary.each do |x|\n",
    "    next x if x == 2\n",
    "    puts x\n",
    "  end\n",
    "  puts \"end\"\n",
    "end\n",
    "func\n",
    "puts\n",
    "\n",
    "def func\n",
    "  ary = [1,2,3]\n",
    "  ary.each do |x|\n",
    "    break x if x == 2\n",
    "    puts x\n",
    "  end\n",
    "  puts \"end\"\n",
    "end\n",
    "func\n",
    "puts\n",
    "\n",
    "def func\n",
    "  ary = [1,2,3]\n",
    "  ary.each do |x|\n",
    "    return x if x == 2\n",
    "    puts x\n",
    "  end\n",
    "  puts \"end\"\n",
    "end\n",
    "func\n",
    "puts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ブロック内のreturn\n",
    "\n",
    "* ブロック内でreturnすると返り値を返すのではなくブロックの処理を終えてしまう"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1の時、ifの条件に合致しなかったためreturnはスルーされる\n",
      "a=1\n",
      "2の時、条件に合致するためreturnでブロックを抜けて2を返す\n",
      "\"func = 2\"\n",
      "\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "1\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "3\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "5\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "7\n",
      "条件に合致しないとき、nextで次の処理に進んでputsを実行\n",
      "\"func2 = [1, 2, 3, 4, 5, 6, 7, 8]\"\n",
      "返り値はary\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  ary = [1,2,3,4,5,6,7,8]\n",
    "  ary.each do |a|\n",
    "    return a if 0 == a % 2\n",
    "    puts \"1の時、ifの条件に合致しなかったためreturnはスルーされる\"\n",
    "    puts \"a=#{a}\"\n",
    "    puts \"2の時、条件に合致するためreturnでブロックを抜けて2を返す\"\n",
    "  end\n",
    "end\n",
    "\n",
    "p \"func = #{func}\"\n",
    "puts \n",
    "\n",
    "def func2\n",
    "  ary = [1,2,3,4,5,6,7,8]\n",
    "  ary.each do |a|\n",
    "    puts \"条件に合致しないとき、nextで次の処理に進んでputsを実行\"\n",
    "    next a if 0 == a % 2\n",
    "    puts a\n",
    "  end\n",
    "end\n",
    "p \"func2 = #{func2}\"\n",
    "puts \"返り値はary\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "source": [
    "## yieldで実行結果の取得\n",
    "\n",
    "* 「{}」に囲まれているのがブロック\n",
    "    * ここのブロックは2を返す\n",
    "    * メソッドfunc\n",
    "        * ブロックの実行結果(yield)と引数の合計3を返している"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "def func x\n",
    "  x + yield\n",
    "end\n",
    "puts func(1){ 2 }\n",
    "\n",
    "### do ～ end の形式でも書ける\n",
    "# func(1) do\n",
    "#   2\n",
    "# end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スコープの生成\n",
    "\n",
    "* ブロックの中で変数に代入された値はブロックの外では参照できない"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "\n",
      "undefined local variable or method `z' for main:Object\n"
     ]
    }
   ],
   "source": [
    "def func x\n",
    "  x + yield\n",
    "end\n",
    "puts func(1){ z = 2 }\n",
    "puts\n",
    "\n",
    "### ブロック内で作成された変数zはブロックの外では参照できない\n",
    "begin\n",
    "  puts z\n",
    "rescue NameError => ex\n",
    "  puts ex\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## クロージャとしてのブロック\n",
    "\n",
    "* クロージャ\n",
    "    * 処理の生成時の環境を束縛するもの\n",
    "* おそらく\n",
    "    * クロージャはブロック(メソッド)の外で作った変数を利用しているブロックのこと\n",
    "    * 束縛はクロージャで使う変数をそれっぽく難しく言ったもの\n",
    "* 挙動\n",
    "    * ブロックの外で変数yに2を代入 (束縛yと表現する？)\n",
    "    * メソッドfuncにブロックを渡し、yieldによりブロックを実行\n",
    "        * このときyの値を取得して更新する\n",
    "        * このyは、ブロックの外と同じy\n",
    "            * <font color=\"red\">値ではなく変数そのものが共有されている</font>\n",
    "* Rubyはメソッド内部から外部の変数を参照できない\n",
    "    * クロージャが呼び出し元の変数を処理に持ち込む数少ない手段の一つ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "def func x\n",
    "  x + yield\n",
    "end\n",
    "\n",
    "### ブロックの外で変数yに値を代入\n",
    "y = 2\n",
    "\n",
    "### このブロック内のyは先ほどのブロックの外の変数yと同一\n",
    "puts func(1){y+=2}\n",
    "\n",
    "### yの値は更新されている\n",
    "puts y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 195,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  yield\n",
    "end\n",
    "\n",
    "x = 3\n",
    "func do\n",
    "  x += 5\n",
    "end\n",
    "\n",
    "puts x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ブロックの引数の指定\n",
    "\n",
    "* funcに1と2を渡す\n",
    "* func内部で以下合計する\n",
    "    * 第一引数の値1\n",
    "    * ブロックの実行結果\n",
    "        * yieldはブロック引数2,3を合計して5を返す\n",
    "* 6が返る\n",
    "    * 引数を渡してブロックを処理するという順番"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n"
     ]
    }
   ],
   "source": [
    "def func a, b\n",
    "  a + yield(b, 3)\n",
    "end\n",
    "\n",
    "puts func(1, 2){|x,y| x+y}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 196,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 196,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def func x, y\n",
    "  x + y + yield\n",
    "end\n",
    "\n",
    "func(1,2){3}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "nil\n",
      "\"a\"\n",
      "true\n",
      "6\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[1, 2, nil, \"a\", true, 6]"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def func *x\n",
    "  x.each{|i| p i}\n",
    "end\n",
    "func(1,2,nil,\"a\",true,6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "nil\n",
      "\"a\"\n",
      "true\n",
      "6\n",
      "\n",
      "x = 1\n"
     ]
    }
   ],
   "source": [
    "def func x, *y\n",
    "  y.each{|i| p i}\n",
    "  puts\n",
    "  puts \"x = #{x}\"\n",
    "end\n",
    "func(1,2,nil,\"a\",true,6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ブロックの判定(ブロックが指定されたかどうか)\n",
    "\n",
    "* block_given?メソッドで実現できる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  return 1 if block_given?\n",
    "  2\n",
    "end\n",
    "\n",
    "puts func(){}\n",
    "puts func"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 206,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "\n",
      "false\n",
      "\n",
      "true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  puts block_given?\n",
    "end\n",
    "puts func{}\n",
    "puts func\n",
    "puts func{nil}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Procの基本\n",
    "\n",
    "* ブロックをオブジェクトとして渡したい時に利用する\n",
    "    * ブロックそのものはオブジェクトではない\n",
    "* 生成\n",
    "    * Procクラスのコンクラスタにブロックを指定すると生成できる\n",
    "* 利用\n",
    "    * Procのインスタンスに対してcallメソッドを使う\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 207,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "proc = Proc.new{|x| puts x}\n",
    "proc.call(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Proc\n",
      "[1, 2]\n",
      "NilClass\n"
     ]
    }
   ],
   "source": [
    "proc = Proc.new{|x| puts x}\n",
    "puts proc.class\n",
    "puts proc.call([1,2]).class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 1, 2]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "proc = Proc.new{|x| puts x * 2}\n",
    "puts proc.call([1,2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Procオブジェクトの生成\n",
    "\n",
    "* 遅延評価\n",
    "    * 処理自体を先に生成して後で評価する\n",
    "    * 例\n",
    "        * カウンタで初期値をプログラム冒頭で決定 : 処理と初期値の設定\n",
    "        * 後の処理でカウントする : 遅延評価"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start= 3\n",
      "up= 1\n",
      "4\n",
      "start= 4\n",
      "up= 3\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "def get_counter start\n",
    "  Proc.new do |up|\n",
    "    puts \"start= #{start}\"\n",
    "    puts \"up= #{up}\"\n",
    "    start += up\n",
    "  end\n",
    "end\n",
    "\n",
    "### 初期値として3を設定。count_upはProcオブジェクトを参照\n",
    "count_up = get_counter(3)\n",
    "\n",
    "### 初期値に1を足す\n",
    "puts count_up.call(1)\n",
    "\n",
    "### さらに3を足す\n",
    "puts count_up.call(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 214,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "proc1 = Proc.new{x += 1}\n",
    "x = 3\n",
    "puts proc1.call(x)\n",
    "puts proc1.call(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Proc ⇔ ブロック 変換\n",
    "\n",
    "* Proc -> ブロック\n",
    "    * Procオブジェクトに「&」をつけて最後の引数に指定する\n",
    "* ブロック -> Proc\n",
    "    * 最後の仮引数に「&」をつけた引数で参照できる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "### Proc -> ブロック\n",
    "def func x\n",
    "  x + yield\n",
    "end\n",
    "proc = Proc.new{2}\n",
    "\n",
    "### 最後の引数に&をつけて渡す\n",
    "puts func(1,&proc)\n",
    "  \n",
    "#=========================#\n",
    "  \n",
    "### ブロック -> Proc\n",
    "### 関数の最後の仮引数に&をつけた名前を渡す\n",
    "def func2 y, &proc2\n",
    "  y + proc2.call\n",
    "end\n",
    "puts func2(3){ 4 }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "def func_a x, &proc1\n",
    "  x + proc1.call\n",
    "end\n",
    "puts func_a(1){ 2 }\n",
    "puts\n",
    "\n",
    "def func_b y\n",
    "  y + yield\n",
    "end\n",
    "puts func_b(3){ 4 }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 217,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "def func\n",
    "  yield\n",
    "end\n",
    "\n",
    "proc = Proc.new{2}\n",
    "puts func(&proc)\n",
    "\n",
    "puts func{3}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 279,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "def func &proc1\n",
    "  proc1.call\n",
    "end\n",
    "puts func{2}\n",
    "\n",
    "def func &proc1\n",
    "  proc(&proc1)\n",
    "end\n",
    "puts func{3}.call\n",
    "\n",
    "def func\n",
    "  yield\n",
    "end\n",
    "puts func{4}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 280,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "def func &lmd1\n",
    "  lambda(&lmd1)\n",
    "end\n",
    "puts func{1}.call\n",
    "\n",
    "def func &lmd2\n",
    "  lmd2.call\n",
    "end\n",
    "puts func{2}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## lambda\n",
    "\n",
    "\n",
    "* lambdaメソッド\n",
    "    * Procインスタンスを生成する\n",
    "        * Procインスタンスはlambdaとも呼ばれる\n",
    "        * Procやブロックよりもメソッドに近い動きをする\n",
    "    * Proc.newで生成したインスタンはprocとも呼ばれる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "lmd = lambda{|x| puts x}\n",
    "lmd.call(1)\n",
    "\n",
    "### Ruby1.9以降の新しい書き方 (アロー演算子)\n",
    "### putsを外出し\n",
    "lmd2 = -> ( x ) { x }\n",
    "puts lmd2.call(2)\n",
    "\n",
    "### putsをブロック内に記載\n",
    "lmd3 = -> (x, y){puts x + y}\n",
    "lmd3.call(3, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "proc1 = Proc.new{|x| puts x}\n",
    "proc1.call(1)\n",
    "\n",
    "lmd1 = lambda{|x| puts x}\n",
    "lmd1.call(2)\n",
    "  \n",
    "lmd2 = -> (x){ puts x}\n",
    "lmd2.call(3)\n",
    "\n",
    "lmd3 = -> (x,y){ puts x; puts y}\n",
    "lmd3.call(4,5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 257,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Proc\n",
      "Proc\n",
      "[Proc, MethodSource::MethodExtensions, MethodSource::SourceLocation::ProcExtensions, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n",
      "[:new]\n",
      "[:proc]\n",
      "[:lambda]\n"
     ]
    }
   ],
   "source": [
    "proc1 = Proc.new{|x| puts x}\n",
    "puts proc1.class\n",
    "\n",
    "lmd1 = lambda{|x| puts x}\n",
    "puts lmd1.class\n",
    "\n",
    "puts Proc.ancestors\n",
    "\n",
    "puts Proc.methods.grep(/new/)\n",
    "puts Kernel.methods.grep(/proc/)\n",
    "puts Kernel.methods.grep(/lambda/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 231,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1mFrom:\u001b[0m proc.c (C Method):\n",
      "\u001b[1mOwner:\u001b[0m #<Class:Proc>\n",
      "\u001b[1mVisibility:\u001b[0m public\n",
      "\u001b[1mSignature:\u001b[0m new(*arg1)\n",
      "\u001b[1mNumber of lines:\u001b[0m 10\n",
      "\n",
      "Creates a new \u001b[1;34;4mProc\u001b[0m object, bound to the current\n",
      "context. \u001b[1;34;4mProc\u001b[0m::new may be called without a block only\n",
      "within a method with an attached block, in which case that block is\n",
      "converted to the \u001b[1;34;4mProc\u001b[0m object.\n",
      "\n",
      "   \u001b[32mdef\u001b[0m \u001b[1;34mproc_from\u001b[0m\n",
      "     \u001b[1;34;4mProc\u001b[0m.new\n",
      "   \u001b[32mend\u001b[0m\n",
      "   proc = proc_from { \u001b[31m\u001b[1;31m\"\u001b[0m\u001b[31mhello\u001b[1;31m\"\u001b[0m\u001b[31m\u001b[0m }\n",
      "   proc.call   \u001b[1;34m#=> \"hello\"\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "show-doc Proc.new"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 259,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1mFrom:\u001b[0m proc.c (C Method):\n",
      "\u001b[1mOwner:\u001b[0m Kernel\n",
      "\u001b[1mVisibility:\u001b[0m private\n",
      "\u001b[1mSignature:\u001b[0m proc()\n",
      "\u001b[1mNumber of lines:\u001b[0m 1\n",
      "\n",
      "Equivalent to \u001b[1;34;4mProc\u001b[0m.new.\n"
     ]
    }
   ],
   "source": [
    "show-doc Kernel#proc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1mFrom:\u001b[0m proc.c (C Method):\n",
      "\u001b[1mOwner:\u001b[0m Kernel\n",
      "\u001b[1mVisibility:\u001b[0m private\n",
      "\u001b[1mSignature:\u001b[0m lambda()\n",
      "\u001b[1mNumber of lines:\u001b[0m 2\n",
      "\n",
      "Equivalent to \u001b[1;34;4mProc\u001b[0m.new, except the resulting Proc objects\n",
      "check the number of parameters passed when called.\n"
     ]
    }
   ],
   "source": [
    "show-doc Kernel#lambda"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Procとlambdaの振る舞いの違い\n",
    "\n",
    "* returnとスコープ\n",
    "    * Procは生成元のスコープを脱出する\n",
    "        * return以降に何らかの処理を行いたい場合はnextなどを駆使してどうにかする\n",
    "    * lambdaはブロック内でreturnすると呼び出し元に復帰する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Procはcallでスコープを脱出するので2まで行かない\n",
      "1\n",
      "lambdaは呼び出し元に戻る\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "puts \"Procはreturnでスコープを脱出するので2まで行かない\"\n",
    "def func_proc\n",
    "  proc = Proc.new{return 1}\n",
    "  puts proc.call\n",
    "  puts 2\n",
    " end\n",
    "puts func_proc\n",
    "\n",
    "puts \"lambdaは呼び出し元に戻るので4まで行く\"\n",
    "def func_lambda\n",
    "  proc = lambda{return 3}\n",
    "  puts proc.call\n",
    "  puts 4\n",
    "end\n",
    "func_lambda"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "* 引数が一致しない場合\n",
    "    * Procは無視、もしくはnilを返す\n",
    "    * lambdaは例外ArgumentErrorが発生する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 281,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "引数が一致しない場合はnil\n",
      "2\n",
      "nil\n",
      "2\n",
      "\n",
      "引数が一致しない場合は例外が発生\n",
      "4\n",
      "wrong number of arguments (given 1, expected 2)\n"
     ]
    }
   ],
   "source": [
    "puts \"引数が一致しない場合はnil\"\n",
    "p1 = Proc.new{|x,y| y}\n",
    "p p1.call(1,2)\n",
    "p p1.call(1)\n",
    "p p1.call(1,2,3)\n",
    "puts\n",
    "\n",
    "puts \"引数が一致しない場合は例外が発生\"\n",
    "l1 = lambda{|x,y| y}\n",
    "p l1.call(3,4)\n",
    "begin\n",
    "  p l1.call(3)\n",
    "rescue ArgumentError => ex\n",
    "  puts ex\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# 配列やハッシュの走査\n",
    "\n",
    "* for式、while式はスコープが作成されないので走査には余り使われない\n",
    "    * 代わりにブロックを受け取るメソッドが使われる\n",
    "* ブロックを受け取るメソッド\n",
    "    * each\n",
    "    * each_with_index\n",
    "    * each_key\n",
    "    * each_value\n",
    "    * upto\n",
    "    * dwonto\n",
    "    * times\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## 配列のeach\n",
    "\n",
    "* each\n",
    "    * メソッドのブロックの引数には要素の値が格納される\n",
    "* each_with_index\n",
    "    * 引数を２つ取る\n",
    "        * 第一引数は要素の値\n",
    "        * 第二引数はインデックス\n",
    "            * 0からはじまる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "value = 1\n",
      "value = 2\n",
      "value = 3\n",
      "index = 0, value = 4\n",
      "index = 1, value = 5\n",
      "index = 2, value = 6\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[4, 5, 6]"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[1,2,3].each do |value|\n",
    "  puts \"value = #{value}\"\n",
    "end\n",
    "\n",
    "[4,5,6].each_with_index do |value, index|\n",
    "  puts \"index = #{index}, value = #{value}\"\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "\n",
      "1\n",
      "2\n",
      "3\n",
      "\n",
      "i = 0, v = 10\n",
      "i = 1, v = 11\n",
      "i = 2, v = 12\n",
      "\n"
     ]
    }
   ],
   "source": [
    "proc1 = Proc.new{|x| puts x}\n",
    "proc1.call([1,2,3])\n",
    "puts\n",
    "[1,2,3].each &proc1\n",
    "puts\n",
    "\n",
    "\n",
    "lmd1 = lambda{|v, i| puts \"i = #{i}, v = #{v}\"}\n",
    "[10,11,12].each_with_index &lmd1\n",
    "puts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ハッシュのeach\n",
    "\n",
    "* each\n",
    "    * 引数を２つ取る\n",
    "        * 第一引数はキー\n",
    "        * 第二引数はバリュー\n",
    "* each_key\n",
    "    * キーのみ\n",
    "* each_value\n",
    "    * バリューのみ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "key = a, value = 1\n",
      "key = b, value = 2\n",
      "引数が一つの場合はキーとバリューの配列ができる\n",
      "x = [:a, 1]\n",
      ":a\n",
      "x = [:b, 2]\n",
      ":b\n",
      "key = c\n",
      "key = d\n",
      "value = 5\n",
      "value = 6\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{:e=>5, :f=>6}"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{a: 1, b: 2}.each do |key, value|\n",
    "  puts \"key = #{key}, value = #{value}\"\n",
    "end\n",
    "\n",
    "puts \"引数が一つの場合はキーとバリューの配列ができる\"\n",
    "{a: 1, b: 2}.each do |x|\n",
    "  puts \"x = #{x}\"\n",
    "  p x[0]\n",
    "end\n",
    "\n",
    "{c: 3, d: 4}.each_key do |key|\n",
    "  puts \"key = #{key}\"\n",
    "end\n",
    "\n",
    "{e: 5, f: 6}.each_value do |value|\n",
    "  puts \"value = #{value}\"\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 290,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{:a=>\"hoge\", :b=>\"fuga\"}\n",
      "k = a, v = hoge\n",
      "k = b, v = fuga\n",
      "x = [:a, \"hoge\"]\n",
      "x = [:b, \"fuga\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{:a=>\"hoge\", :b=>\"fuga\"}"
      ]
     },
     "execution_count": 290,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hash = {a: \"hoge\", b: \"fuga\"}\n",
    "puts hash\n",
    "\n",
    "hash.each{|k,v| puts \"k = #{k}, v = #{v}\"}\n",
    "hash.each{|x| puts \"x = #{x}\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## 範囲オブジェクトのeach\n",
    "\n",
    "範囲内を繰り返す"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a\n",
      "b\n",
      "c\n",
      "d\n",
      "\n",
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"1\"...\"4\""
      ]
     },
     "execution_count": 139,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(\"a\"..\"d\").each do |value|\n",
    "  puts value\n",
    "end\n",
    "puts\n",
    "\n",
    "(\"1\"...\"4\").each do |value|\n",
    "  puts value\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 296,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "\n",
      "a\n",
      "b\n",
      "c\n",
      "d\n",
      "e\n",
      "f\n",
      "g\n",
      "h\n",
      "i\n",
      "j\n",
      "k\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"a\"..\"k\""
      ]
     },
     "execution_count": 296,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(1..5).each{|x| puts x}\n",
    "puts\n",
    "(\"1\"..\"5\").each{|x| puts x}\n",
    "puts\n",
    "(\"a\"..\"k\").each{|x| puts x}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## upto, downto,timesメソッド"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "4\n",
      "8\n",
      "7\n",
      "6\n",
      "Hello\n",
      "Hello\n",
      "Hello\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2.upto(4) do |x|\n",
    "  puts x\n",
    "end\n",
    "\n",
    "8.downto(6) do |x|\n",
    "  puts x\n",
    "end\n",
    "\n",
    "3.times do |x|\n",
    "  puts \"Hello\"\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 299,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello\n",
      "hello\n",
      "hello\n",
      "a\n",
      "b\n",
      "c\n",
      "d\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"a\""
      ]
     },
     "execution_count": 299,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3.times{puts \"hello\"}\n",
    "\n",
    "\"a\".upto(\"d\"){|s| puts s}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.3.1",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.3.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
